<!doctype html>
<html lang="zh">
<head>
  <meta charset="utf-8">
  <title>KISSY - 全终端适配的 JS 类库</title>
  <meta name="viewport" content="width=device-width">
  <link href="http://fonts.googleapis.com/css?family=Droid+Sans|Lekton|Ubuntu+Mono:400,700" rel="stylesheet">
	<link rel="stylesheet" href="templates/assets/bootstrap.css">
	<link href="templates/assets/normalize.css" rel="stylesheet">
	<link href="templates/assets/kissy.css" rel="stylesheet">
	<link href="templates/assets/prettify.css" rel="stylesheet">
	<link href="templates/assets/forkit.css" rel="stylesheet">
	<script src="templates/assets/jquery.min.js"></script>
	<script src="templates/assets/script.js" type="text/javascript"></script>
	<script src="http://g.tbcdn.cn/trip/kissy/1.4.0/seed-min.js"></script>
	<script src="api/assets/highlight.pack.js"></script>
	<link href="api/assets/tomorrow-night-bright.css" rel=stylesheet />
	<link rel="shortcut icon" href="http://a.tbcdn.cn/s/kissy/favicon.ico">
</head>

<body class="">
    <nav id="sidebar">
    <header>
		<a href="index.html">
			<!--img src="http://gtms04.alicdn.com/tps/i4/T1ceiPFbpcXXcljp_h-200-89.png"-->
			<!--img src="templates/assets/img/logo_6.png"-->
			<!--img src="http://gtms04.alicdn.com/tps/i4/T14oa2FcNcXXaOySEh-180-104.png" alt="" /-->
			<!--img src="http://gtms01.alicdn.com/tps/i1/T1Amq1FaXgXXbXVSUh-180-127.png" alt="" /-->
			<img src="http://gtms02.alicdn.com/tps/i2/T1N0jTXXXjXXay7Rri-175-78.png" alt="" />
		</a>
	</header>
    <ul>
      <li class="nav-divider"><a href="index.html"><img src="templates/assets/img/icon-home.png">首页</a></li>
      <li class="nav-divider"><a href="why-kissy.html"><img src="templates/assets/img/icon-why.png">Why KISSY?</a></li>
      <li><a href="get-started.html"><img src="templates/assets/img/icon-getting-started.png">KISSY 1.4.x 教程大纲</a></li>
      <li class="nav-sub"><a href="module-map.html">核心模块列表</a></li>
      <li class="nav-sub"><a href="kmd.html">KISSY 模块规范 (KMD)</a></li>
      <li class="nav-sub"><a href="gbs.html">浏览器兼容基准(GBS)</a></li>
      <li class="nav-sub"><a href="http://cyj.me/jquery-kissy-rosetta/">jQuery KISSY 对比手册</a></li>
      <li class="nav-sub"><a href="http://gallery.kissyui.com/guide">KISSY 组件开发规范</a></li>
      <li class="nav-sub nav-divider"><a href="history.html">历史版本</a></li>
      <li><a href="">API Doc</a></li>
      <li><a href="http://demo.kissyui.com">Demos</a></li>
      <li class="nav-divider"><a href="http://gallery.kissyui.com">KISSY Gallery</a></li>
      <li><a href="tools.html">KISSY 项目构建工具</a></li>
      <li class="nav-sub"><a href="kmc.html">KS Module Compiler</a></li>
      <li class="nav-sub"><a href="http://abc.f2e.taobao.net">ABC</a></li>
      <li class="nav-sub nav-divider"><a href="clam.html">Clam</a></li>
      <li><a href="third-party-lib.html">第三方代码库</a></li>
      <li class="nav-sub"><a href="https://github.com/lorrylockie/tpap/wiki">面向第三方安全的 KISSY</a></li>
      <li class="nav-sub"><a href="http://www.builive.com/demo/index.php">BUI</a></li>
      <li class="nav-sub nav-divider"><a href="http://work.tmall.net/muidoc/build/">MUI</a></li>
      <li><a href="https://github.com/kissyteam/kissy/blob/master/CONTRIBUTING.md">为 KISSY Core 贡献代码</a></li>
      <li class="nav-sub"><a href="http://google-styleguide.googlecode.com/svn/trunk/htmlcssguide.xml">HTML/CSS编码规范</a></li>
      <li class="nav-sub nav-divider"><a href="http://docs.kissyui.com/source/tutorials/style-guide/google/javascriptguide.xml">JavaScript 编码规范</a></li>
	  <li><a href="upgrade.html"><img src="templates/assets/img/icon-documentation.png">1.3.x->1.4.0 升级指南</a></li>
	  <li><a href="faq.html"><img src="templates/assets/img/icon-faqs.png">FAQ</a></li>
      <li><a href="https://github.com/kissyteam/kissy"><img src="templates/assets/img/icon-github.png">GitHub</a></li>
	  <li><a href="core-team.html"><img src="templates/assets/img/icon-google-plus.png">KISSY 核心小组</a></li>
    </ul>
  </nav>

  <div id="content">
    <article>
      

	<h1>KISSY 中的面向对象</h1>
<p>JavaScript 语言自成体系，自有一套代码重用的模式，这些常见的代码重用模式可以在《Javascript 设计模式》、《JavaScript 编程模式》中找到理论基础。KISSY 即是实践了这些典型的代码重用模式，并作为 KISSY 代码库的面向对象的核心，向高层代码提供语言的完备性支撑。</p>
<p>这些理论基础大都来自<a href="https://speakerdeck.com/lijing00333/javascript-patterns">&quot;javascript 编程模式&quot;</a>一书：</p>
<p><img src="http://gtms01.alicdn.com/tps/i1/T1mumMFdBdXXXMOITY-406-251.png" alt=""></p>
<p>KISSY 中面向对象的范畴包含两个方面，本篇讲解第一方面</p>
<ul>
<li>语言层面：JS 语言特有的编程模式<ul>
<li>面向对象相关的模式</li>
<li>JS 语言增强的工具函数</li>
</ul>
</li>
<li>最佳实践：KISSY 对于面向UI、模块生命周期的封装，包括组件模式、插件模式等</li>
</ul>
<h2>概要</h2>
<p>JavaScript 语言没有原生类的概念，对象之间共享方法的关键渠道是通过原型。而具备某一类原型方法的&#39;模板对象&#39;，通常被称作基类，子类除了调用基类的构造器（手动调用）外，最重要的就是要拥有基类的行为能力（继承基类原型上的方法）。这个过程中涉及到五种典型的行为：</p>
<ul>
<li>混合 mix</li>
<li>克隆 clone</li>
<li>扩充 augment</li>
<li>继承 extend</li>
<li>合并 merge</li>
</ul>
<p>对比下YUI和KISSY的这几个方法名的差别</p>
<table class="table table-condensed">
<thead>
    <tr>
        <th>
            <strong>YUI</strong>
        </th>
        <th>
            <strong>KISSY</strong>
        </th>
    </tr>
</thead>
<tbody>
    <tr>
        <td>
            augmentObject
        </td>
        <td>
            mix
        </td>
    </tr>
    <tr>
        <td>
            augmentProto
        </td>
        <td>
            augment
        </td>
    </tr>
    <tr>
        <td>
            merge
        </td>
        <td>
            merge
        </td>
    </tr>
    <tr>
        <td>
            extend
        </td>
        <td>
            extend
        </td>
    </tr>
    <tr>
        <td>
            clone
        </td>
        <td>
            clone
        </td>
    </tr>
</tbody>
</table>

<p>以 kissy 的 API 为例，merge 和 augment 都是基于 mix 方法，本质上利用了 JS 的动态特性，在运行时为对象增减成员；</p>
<p>extend 方法的实现比较典型，总体思路是子构造器的原型对象指向父构造器的一个实例，具体有一些细节问题要处理。类继承体系中继承的是对象的模板（即类），JS 没有对于对象的更高一层的抽象数据结构，即使有 constructor 这种东西，它本身也只是 function 对象而已。</p>
<h3>mix</h3>
<p><code>mix (receiver , supplier [ , overwrite = true , whitelist , deep ]) =&gt; Object</code></p>
<p>将 supplier 对象的成员复制到 receiver 对象上。参数：</p>
<ul>
<li>receiver (object) – 属性接受者对象.</li>
<li>supplier (object) – 属性来源对象.</li>
<li>overwrite (boolean) – 是否覆盖接受者同名属性.</li>
<li>whitelist (Array<string>) – 属性来源对象的属性白名单, 仅在名单中的属性进行复制.</li>
<li>deep (boolean) – 是否进行深度 mix (deep copy)</li>
</ul>
<p>mix 默认不是递归进行的. 如果其中一个属性为对象或者数组，那么他将会被接下来对象的同名属性对应的值所代替，即值不会被合并。 如果设置了参数 deep = true ，那么会对数组和简单对象<code>KISSY.isPlainObject()</code>递归合并.</p>
<p>supplier undefined 的属性值不会被复制，不过对象从原型继承下来下的值则会被复制.    </p>
<blockquote>
<p>该方法仅适用于 javascript 对象，不要再浏览器对象上调用，例如 node.style</p>
</blockquote>
<p>简单 mix</p>
<pre><code>var S = KISSY,
r = { a: &#39;a&#39;, b: &#39;b&#39; };

S.mix(r, { c: &#39;c&#39; });
S.log(r.c); // =&gt; &#39;c&#39;

S.mix(r, { a: &#39;a2&#39; }, false);
S.log(r.a); // =&gt; &#39;a&#39;

S.mix(r, { e: &#39;e&#39;, f: &#39;f&#39; }, true, [&#39;f&#39;]);
S.log(r.e); // =&gt; undefined
S.log(r.f); // =&gt; &#39;f&#39;</code></pre>
<p>深度mix</p>
<pre><code>var object1 = {
  apple: 0,
  banana: {weight: 52, price: 100},
  cherry: 97
};
var object2 = {
  banana: {price: 200},
  durian: 100
};

/* merge object2 into object1, recursively */
S.mix(object1,object2,undefined,undefined,true);

S.log(object1); // =&gt; { apple: 0, banana: { weight: 52, price: 200 }, cherry: 97, durian: 100 }</code></pre>
<p>mix是最自然也是最简单的为 JS 对象添加特性的方式，具体实现就是将一个对象的（所有或指定）属性指向给另一个对象，在静态语言中是无能为力的。</p>
<p>虽然 Yahoo 将这种方式学院式地命名为“augmentObject”并且声称使用它的合适场合是在“扩充一个‘静态类’”时。所谓“静态类”这种说法，只能说是中静态类语言的遗毒太深，什么概念都要一一映射至其上。事实上，“静态类”对应 JS 中的概念是“非构造器对象”，比如字面量对象。而之所以 Yahoo 强调“静态类”，那是因为“静态类”和构造器之间间有一个显区别，前者没有 prototype 属性。</p>
<p>补充一点，“静态类”也可以是构造器，只不过它的 prototype 没有多大意义（比如指向 {}）。</p>
<p>事实上，这个方法是 augment 和 merge 的基础。可以看到，JS 中直接对对象进行各种操作其实非常方便，类什么的都是浮云。</p>
<h3>merge</h3>
<p><code>merge (s1,s2[,...]) =&gt; Object</code></p>
<p>将多个对象的成员合并到一个新对象上. 参数中, 后面的对象成员会覆盖前面的。如果用mix混合对象时，receiver 会被改变，如果想要保留原始的 receiver ，可以使用 KISSY.merge()</p>
<pre><code>var object=S.merge(object1,object2);</code></pre>
<p>简单例子：</p>
<pre><code>var S = KISSY,
a = { a: &#39;a&#39; },
b = { b: &#39;b&#39; },
c = { b: &#39;b2&#39;, c: &#39;c&#39; };

var o = S.merge(a, b, c);
S.log(o.a); // =&gt; &#39;a&#39;
S.log(o.b); // =&gt; &#39;b2&#39;
S.log(o.c); // =&gt; &#39;c&#39;</code></pre>
<p>简单情况下 merge 方法常用来合并配置信息. 推荐使用 Base 处理属性配置.</p>
<h3>extend</h3>
<p><code>extend (r,s[,px,sx]) =&gt; Function</code></p>
<p>让函数对象 r 继承函数对象 s，参数</p>
<ul>
<li>r (function) – receiver,将要继承的子类函数</li>
<li>s (function|object) – supplier,继承自的父类函数</li>
<li>px (object) – prototype members, 需要添加/覆盖的原型成员</li>
<li>sx (object) – static members, 需要添加/覆盖的静态成员.</li>
</ul>
<pre><code>var S = KISSY;

function Bird(name) { this.name = name; }
Bird.prototype.fly = function() { alert(this.name + &#39; is flying now!&#39;); };

function Chicken(name) {
    Chicken.superclass.constructor.call(this, name);
}
S.extend(Chicken, Bird,{
    fly:function(){
        Chicken.superclass.fly.call(this)
        alert(&quot;it&#39;s my turn&quot;);
    }
});

new Chicken(&#39;kissy&#39;).fly();</code></pre>
<p>extend 方法是 KISSY 里类继承的实现方式. 书写 JavaScript 代码时, 请忘记传统 OO 里的继承体系。子类方法中可通过 superclass 来访问父类函数的原型, 进而调用父类方法.</p>
<p>S.extend 像 Node.js 里的 util.inherits，就是用于声明两个类的继承关系，与 util.inherits 相比，它更为贴心，还会维护 superclass 和 superclass.constructor。</p>
<p>注意构造函数体内，通过 Chicken 类上的 superclass 属性，子类不再需要显式写明父类的名称， 只需要直接调 <code>SubClass.superclass.constructor.call(this, attrs)</code> 即可。</p>
<p>而在方法内，也可以通过 SubClass.superclass 拿到父类上的方法，类似其他编程语言中的 super 之类。</p>
<h3>augment</h3>
<p><code>augment(r, s1 [, s2 , ...], ov = true, wl) =&gt; Function</code></p>
<p>将 s1,s2.... 的 <code>prototype</code> 属性的成员复制到 <code>r.prototype</code> 上。这时被复制的成员来自于一个Fucntion对象，这个对象一般被称为掺元类（mixin class）。比如 KISSY 里的 CustemEvent 就是一个掺元类。掺元类只是被扩充用的。参数说明：</p>
<ul>
<li>r (function) – 将要扩充的函数</li>
<li><code>...s1</code> (function|object) – 扩充来源函数或对象. 非函数对象时复制的就是 s 的成员.</li>
<li>ov (boolean) – 是否覆盖 r.prototype 同名属性.</li>
<li>whitelist (Array<string>) – 属性来源对象的属性白名单, 仅在名单中的属性进行复制.</li>
</ul>
<pre><code>var S = KISSY,
Shoutable = {
    shout: function() { alert(&#39;I am &#39; + this.name + &#39;.&#39;); }
};

function Dog(name) { this.name = &#39;Dog &#39; + name; }
function Pig(name) { this.name = &#39;Pig &#39; + name; }

S.augment(Dog, Shoutable);
S.augment(Pig, Shoutable);

new Dog(&#39;Jack&#39;).shout(); // =&gt; I am Dog Jack.
new Pig(&#39;Mary&#39;).shout(); // =&gt; I am Pig Mary.</code></pre>
<p>augment 方法在 KISSY 里非常基础非常重要. 传统 OO 语言里, 可以通过继承或接口来实现共性方法. 在 JavaScript 里, 通过 mixin 特性, 一切变得更简单. augment 是动态语言 mixin 特性的体现, 灵活运用, 能让代码非常优雅简洁.</p>
<p>YUI 中的叫法很长，augmentProto 只扩充 prototype 中的属性，因此扩充的对象必须是“类”。扩充者和被扩充者之间没有半分钱关系，降低了 extend 体系中的复杂耦合，这和“组合优于继承”的 OO 原则是一致的。</p>
<h3>clone</h3>
<p>对象的值的拷贝，绕过引用的拷贝。</p>
<p>参照 <a href="lang.html#clone">lang</a>。</p>
<hr>
<p>有了 S.augment，我们可以很方便得扩展类的原型；有了 S.extend，我们可以很方便地继承；那么 KISSY 对属性 getter、setter 有什么好的解决方案么？答案自然是 Base。</p>
<p>顾名思义，Base 是个基础类；而这个类，也是通过 S.augment 等搞定的。在<a href="base.html">Base</a>小节讲解。</p>


<div id="disqus_thread"></div>
<script>
    if((window.location.hostname.indexOf("kissyui.com")!=-1 )&& window.localStorage.getItem("kissy-commment")!="0"){
    /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
    var disqus_shortname = 'kissy-docs'; // required: replace example with your forum shortname

    // The following are highly recommended additional parameters. Remove the slashes in front to use.
     //var disqus_identifier = '/anim';
     //var disqus_url = window.location;

    /* * * DON'T EDIT BELOW THIS LINE * * */
    (function() {
        var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
        dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js';
        (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
    })();
    }
</script>



      
  <style>
	.github-btn {
		border: 0 none;
		overflow: hidden;
		margin-top:4px;
	}
	footer {
		border-top:1px solid #e2e2e2;
		padding-top:20px;
		clear:both;
	}
	/* iPhone 及以下 */
	@media only screen and (max-width: 767px) {
		.github-link {
			display:none;
		}
	}
  </style>
  <footer>




	<div class="text-center">
		©2013 - 2033 KISSY UI LIBRARY
		<br /> <iframe class="github-btn" src="http://ghbtns.com/github-btn.html?user=kissyteam&amp;repo=kissy&amp;type=watch&amp;count=true" width="100" height="20" title="Star on GitHub"></iframe> 
	<iframe class="github-btn" src="http://ghbtns.com/github-btn.html?user=kissyteam&amp;repo=kissy&amp;type=fork&amp;count=true" width="102" height="20" title="Fork on GitHub"></iframe>
	</div>
  </footer>
    </article>
  </div>
  <a target="_blank" href="https://github.com/kissyteam/kissy" class="github-link"><img alt="Fork me on GitHub" src="http://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" style="position: absolute; top: 0; right: 0; border: 0; z-index: 50"></a>
  <script>
	var S = KISSY;
	(function(){
		S.use('node',function(S){
			S.all('code').each(function(node){
				var className = node.attr('class');
				if(/^lang-/.test(className)){
					var tc = className.replace(/^lang-/,'');
					node.replaceClass(className,tc);
				}
			});
			hljs.tabReplace = '    ';
			hljs.initHighlighting();
		});
	})();
	(function(){
		var h3s = document.getElementsByTagName('h3');
		for(var i = 0;i<h3s.length;i++){
			var str = S.trim(h3s[i].innerHTML);
			try{
				str = str.match(/\w+/)[0];
			}catch(e){
				continue;
			}
			h3s[i].innerHTML = '<a name="'+str+'"></a>' + h3s[i].innerHTML;
		}
	})();
  </script>
</body>
</html>
